/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.ppm.dat.model;

import bgu.ppm.dat.model.impl.AbstractField;
import bgu.ppm.dat.model.impl.SimplePivot;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Set;

/**
 *
 * @author User
 */
public class PivotTestUtils {

    public static Pivot readPivotFromCSV(String filename) throws Exception {
        try (InputStream is = new FileInputStream(filename)) {
            return readPivotFromCSV(is);
        }
    }

    public static Pivot readPivotFromCSV(InputStream stream) throws Exception {
        Scanner s = new Scanner(stream);

        String line = s.nextLine();

        LinkedList<String> headers = new LinkedList<>();

        for (String v : line.split(",")) {
            headers.add(v.trim());
        }

        final int size = headers.size();

        LinkedList<Object[]> data = new LinkedList<>();

        while (s.hasNext()) {
            line = s.nextLine();
            Object[] row = new Object[size];
            int i = 0;
            for (String v : line.split(",")) {
                try {
                    row[i] = Float.valueOf(v.trim());
                } catch (NumberFormatException e) {
                    row[i] = v.trim();
                }
                i++;
            }
            data.add(row);
        }

        SimplePivot p = new SimplePivot(data);

        Set<Field> fields = new HashSet<>();

        int i = 0;
        for (String v : headers) {
            fields.add(generateField(p, i, v, data.getFirst()[i].getClass()));
            i++;
        }

        p.setAvailableRawFields(fields);
        p.setAggregationFunctions(generateAggregatorFunctions());

        return p;
    }

    public static Pivot generateSimplePivot1() {
        ArrayList<Object[]> data = new ArrayList<>();

        data.add(new Object[]{1, "x", 1, "x"});
        data.add(new Object[]{2, "x", 1, "x"});
        data.add(new Object[]{3, "y", 1, "x"});
        data.add(new Object[]{4, "y", 2, "x"});
        data.add(new Object[]{5, "x", 2, "y"});
        data.add(new Object[]{6, "x", 2, "y"});
        data.add(new Object[]{7, "y", 1, "y"});
        data.add(new Object[]{8, "y", 1, "y"});
        data.add(new Object[]{9, "x", 1, "x"});
        data.add(new Object[]{10, "x", 2, "x"});
        data.add(new Object[]{11, "y", 2, "x"});
        data.add(new Object[]{12, "y", 2, "x"});

        SimplePivot<Object[]> p = new SimplePivot<>(data);

        final Field f1 = generateField(p, 0, Integer.class);
        final Field f2 = generateField(p, 1, String.class);
        final Field f3 = generateField(p, 2, Integer.class);
        final Field f4 = generateField(p, 3, String.class);
        p.setAvailableRawFields(new HashSet(Arrays.<Field>asList(f1, f2, f3, f4)));
        p.setAggregationFunctions(generateAggregatorFunctions());
        p.selectAxisField(f3);
        p.selectFilterField(f4);
        p.getSelectedFilterFields().iterator().next().restrictValue("y");
        p.selectSeriesField(f2);
        p.selectValuesField(f1);

//        p.selectFilterField(f1);
//        p.selectFilterField(f2);
//        p.selectFilterField(f3);
//        p.selectFilterField(f4);
        return p;

    }

    public static Pivot generateSimplePivot2() {
        int[] generator = new int[]{2, 3, 4, 5, 6, 7};

        ArrayList<Integer[]> data = generateRawData(generator);
        SimplePivot p = new SimplePivot(data);

        Set<Field> rawFields = generateFields(p, generator);
        p.setAggregationFunctions(generateAggregatorFunctions());
        p.setAvailableRawFields(rawFields);

//        System.out.println("" + joinI(data));
        int turn = 0;

        for (Field f : (Set<Field>) p.getAvailableRawFields()) {
            if (turn < 2) {
                p.selectAxisField(f);
            } else if (turn < 4) {
                final Field ff = f;
                p.selectValuesField(ff);
            } else {
                p.selectSeriesField(f);
            }
            turn++;
        }

        return p;
    }

    private static Field generateField(Pivot pivot, final int fi, Class clazz) {
        return new AbstractField<Object, Object[]>(pivot, "Field " + fi, fi, clazz) {
            @Override
            public Object getValue(Object[] o) {
                return o[fi];
            }
        };
    }

    private static Field generateField(Pivot pivot, final int fi, String name, Class clazz) {
        return new AbstractField<Object, Object[]>(pivot, name, fi, clazz) {
            @Override
            public Object getValue(Object[] o) {
                return o[fi];
            }
        };
    }

    private static ArrayList<Integer[]> generateRawData(int[] generator) {
        ArrayList<Integer[]> data = new ArrayList<>();
        int size = 1;

        for (int t : generator) {
            size *= t;
        }

        for (int i = 0; i < size; i++) {
            Integer[] row = new Integer[generator.length];

            for (int j = 0; j < generator.length; j++) {
                row[j] = 10 * generator[j] + i % generator[j];
            }

            data.add(row);
        }

        return data;
    }

    private static Set<Field> generateFields(Pivot pivot, int[] generator) {
        Set<Field> rawFields = new HashSet<>();

        for (int i = 0; i < generator.length; i++) {
            rawFields.add(generateField(pivot, i, Integer.class));
        }

        return rawFields;
    }

    private static Set<AggregationFunction> generateAggregatorFunctions() {
        Set<AggregationFunction> result = new HashSet<>();

        result.add(new AggregationFunction() {
            @Override
            public String getName() {
                return "Sum";
            }

            @Override
            public Object aggregate(Iterable values) {
                int sum = 0;

                for (Object v : values) {
                    sum += (Float) v;
                }

                return sum;
            }

            @Override
            public String toString() {
                return getName();
            }
        });

        result.add(new AggregationFunction() {
            @Override
            public String getName() {
                return "Avg";
            }

            @Override
            public Object aggregate(Iterable values) {
                int sum = 0;
                int num = 0;

                for (Object v : values) {
                    sum += (Float) v;
                    num++;
                }

                return (double) sum / (double) num;
            }

            @Override
            public String toString() {
                return getName();
            }
        });

        return result;
    }
}
